package edu.ccut.saturn.studio.wfg.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.part.FileEditorInput;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import edu.ccut.saturn.studio.core.util.xml.SaturnW3CUtil;
import edu.ccut.saturn.studio.export.createhtml.Parameters;
import edu.ccut.saturn.studio.logic.model.BasicShape;
import edu.ccut.saturn.studio.logic.model.IShapeSearcher;
import edu.ccut.saturn.studio.wfg.ShapesPlugin;
import edu.ccut.saturn.studio.wfg.dialog.SelectionCandidate;
import edu.ccut.saturn.studio.wfg.wfgmodel.FormDataAttribute;
import edu.ccut.saturn.studio.wfg.wfgmodel.SaturnAttribute;
import edu.ccut.saturn.studio.wfg.wfgmodel.SaturnHumanNode;
import edu.ccut.saturn.studio.wfg.wfgmodel.SaturnStartNode;

public abstract class Shape extends BasicShape implements IShapeSearcher {

	public static final String KEY_ATTRIBUTE_X = "x";

	public static final String KEY_ATTRIBUTE_Y = "y";
	
	public static final String KEY_ATTRIBUTE_ID = "id";
	
	public static final String KEY_ATTRIBUTE_SHAPE_NEXT_ID = "next";
	
	public static final String KEY_NODE_NAME = "name";
	
	public static final String KEY_NODE_DESCRIPTION = "description";
	
	public static final String KEY_NODE_CONNECTION = "connection";

	public static final String KEY_CONNECTION_ATTRIBUTE_SOURCE = "source";

	public static final String KEY_CONNECTION_ATTRIBUTE_TARGET = "target";

	public static final String LOCATION_PROP = "Shape.Location";

	public static final String SIZE_PROP = "Shape.Size";

	public static final String NAME_PROP = "Shape.Name";

	public static final String SOURCE_CONNECTIONS_PROP = "Shape.SourceConn";

	public static final String TARGET_CONNECTIONS_PROP = "Shape.TargetConn";

	private String id = "";

	private String nextId = "";

	private String name = "";

	private Point location = new Point(0, 0);

	private Dimension size = new Dimension(50, 70);

	private List<Connection> sourceConnections = new ArrayList<Connection>();

	private List<Connection> targetConnections = new ArrayList<Connection>();
	
	private String description = "";

	protected static Image createImage(String name) {
		InputStream stream = ShapesPlugin.class.getResourceAsStream(name);
		Image image = new Image(null, stream);
		try {
			stream.close();
		} catch (IOException ioe) {
		}
		return image;
	}

	public void addConnection(Connection conn) {

		if (conn == null || conn.getSource() == conn.getTarget()) {
			throw new IllegalArgumentException();
		}
		
		if (conn.getSource() == this) {
			sourceConnections.add(conn);
			firePropertyChange(SOURCE_CONNECTIONS_PROP, null, conn);
		} else if (conn.getTarget() == this) {
			targetConnections.add(conn);
			firePropertyChange(TARGET_CONNECTIONS_PROP, null, conn);
		}
	}

	public abstract Image getIcon();
	
	public abstract Image getSmallIcon();

	public Point getLocation() {
		return location.getCopy();
	}

	public Dimension getSize() {
		return size.getCopy();
	}

	public List<Connection> getSourceConnections() {
		return new ArrayList<Connection>(sourceConnections);
	}

	public List<Connection> getTargetConnections() {
		return new ArrayList<Connection>(targetConnections);
	}

	public void removeConnection(Connection conn) {
		if (conn == null) {
			throw new IllegalArgumentException();
		}
		if (conn.getSource() == this) {
			sourceConnections.remove(conn);
			firePropertyChange(SOURCE_CONNECTIONS_PROP, null, conn);
		} else if (conn.getTarget() == this) {
			targetConnections.remove(conn);
			firePropertyChange(TARGET_CONNECTIONS_PROP, null, conn);
		}
	}

	public void setLocation(Point newLocation) {
		if (newLocation == null) {
			throw new IllegalArgumentException();
		}
		location.setLocation(newLocation);
		firePropertyChange(LOCATION_PROP, null, location);
	}
	
	public void setSize(Dimension newSize) {
		if (newSize != null) {
			size.setSize(new Dimension(50, 70));
			firePropertyChange(SIZE_PROP, null, size);
		}
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
		firePropertyChange(NAME_PROP, null, name);
	}

	public String getId() {
		return id;
	}

	public void setId(String shapeId) {
		this.id = shapeId;
	}

	public String getNextId() {
		return nextId;
	}

	public void setNextId(String nextId) {
		this.nextId = nextId;
	}

	public abstract IFigure getFigure();
	
	public abstract Dialog getDialog();

	public abstract Node doRefresh(Document document);

	public final void refresh(Document document) {
		Node node = this.doRefresh(document);

		this.createBaseInfo(document, node);
		this.createConnections(document);
	}

	public String toString() {
		return this.name;
	}

	private void createBaseInfo(Document document, Node node) {
		SaturnW3CUtil.createAttribute(node, KEY_ATTRIBUTE_ID, this.id);
		SaturnW3CUtil.createAttribute(node, KEY_ATTRIBUTE_SHAPE_NEXT_ID, this.nextId);
		SaturnW3CUtil.createAttribute(node, KEY_ATTRIBUTE_X,""+this.getLocation().x);
		SaturnW3CUtil.createAttribute(node, KEY_ATTRIBUTE_Y, ""+this.getLocation().y);
		SaturnW3CUtil.createChildNode(node, KEY_NODE_NAME,this.name);
		SaturnW3CUtil.createChildNode(node, KEY_NODE_DESCRIPTION,this.description);
	}
	
	private void createConnections(Document document) {
		Element root = document.getDocumentElement();

		for (Connection connection : this.sourceConnections) {
			Node connectionNode = document.createElement(KEY_NODE_CONNECTION);
			SaturnW3CUtil.createAttribute(connectionNode,
					KEY_CONNECTION_ATTRIBUTE_SOURCE, connection.getSource()
							.getId());

			SaturnW3CUtil.createAttribute(connectionNode,
					KEY_CONNECTION_ATTRIBUTE_TARGET, connection.getTarget()
							.getId());
			root.appendChild(connectionNode);
		}
	}

	public int getNumber(String expect, String[] classtype) {
		if (expect != null) {
			for (int i = 0; i < classtype.length; i++) {
				if (classtype[i].equals(expect)) {
					return i;
				}
			}
		}
		return -1;
	}
	
	protected void createNodes(Document document, Node node,
			List<SaturnAttribute> parameters,String nodeName,String childName) {
		Node parametersNode = document.createElement(nodeName);
		if (parameters != null) {
			for (SaturnAttribute parameter : parameters) {
				Node parameterNode = createChildNode(document,parameter,childName);
				parametersNode.appendChild(parameterNode);
			}
		}
		node.appendChild(parametersNode);
	}
	
	protected abstract Node createChildNode(Document document,SaturnAttribute attrib,String name);
	
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}
	
	/**
	 * 得到formData的key列表
	 * 
	 * */
	public String[] getFormDataList(){
		Set<String> valueList = new HashSet<String>();
		ShapesDiagram sd = (ShapesDiagram) this.getParent();
		List<Shape> childShapes = sd.getShapes();
		for(Shape shape: childShapes){
			if(shape instanceof SaturnStartNode){
				List<SaturnAttribute> formDataList = ((SaturnStartNode) shape).getFormDataAttributeList();
				if(formDataList != null){
					for(int i = 0; i < formDataList.size(); i++){
						FormDataAttribute fd = (FormDataAttribute) formDataList.get(i);
						if(!"".equals(fd.getKey().trim())){
							valueList.add(fd.getKey().trim());
						}
					}
				}
			}
			if(shape instanceof SaturnHumanNode){
				List<SaturnAttribute> formDataList = ((SaturnHumanNode) shape).getFormDataAttributeList();
				if(formDataList != null){
					for(int i = 0; i < formDataList.size(); i++){
						FormDataAttribute fd = (FormDataAttribute) formDataList.get(i);
						if(!"".equals(fd.getKey().trim())){
							valueList.add(fd.getKey().trim());
						}
					}
				}
			}
		}
		String[] ss = new String[valueList.size()];
		ss = valueList.toArray(ss);
		return ss;
	}
	
	/**
	 * 根据formData的key寻找其他基本信息
	 * 
	 * */
	public String[] getFormDataInformationByKey(String key){
		ShapesDiagram sd = (ShapesDiagram) this.getParent();
		List<Shape> childShapes = sd.getShapes();
		for(Shape shape: childShapes){
			if(shape instanceof SaturnStartNode){
				List<SaturnAttribute> formDataList = ((SaturnStartNode) shape).getFormDataAttributeList();
				for(int i = 0; i < formDataList.size(); i++){
					FormDataAttribute fd = (FormDataAttribute) formDataList.get(i);
					if(key.equals(fd.getKey().trim())){
						return new String[]{fd.getName(),fd.getType(),fd.getAccessType(),fd.getRequired()};
					}
				}
			}
			if(shape instanceof SaturnHumanNode){
				List<SaturnAttribute> formDataList = ((SaturnHumanNode) shape).getFormDataAttributeList();
				for(int i = 0; i < formDataList.size(); i++){
					FormDataAttribute fd = (FormDataAttribute) formDataList.get(i);
					if(key.equals(fd.getKey().trim())){
						return new String[]{fd.getName(),fd.getType(),fd.getAccessType(),fd.getRequired()};
					}
				}
			}
		}
		
		return new String[]{"",
				SelectionCandidate.formDataTypes[0],
				SelectionCandidate.formDataReadWrite[0],
				SelectionCandidate.formDataRequired[0]};
	}
	
	/**
	 * 获得模型所在工程
	 * 
	 * @return
	 */
	public IProject findTheProject() {
		String iproject = ((FileEditorInput) ((ShapesDiagram) this.getParent()).
				getEditor().getEditorInput()).getPath().toString();
		String[] workspace = ResourcesPlugin.getWorkspace().getRoot()
				.getLocation().toString().split("/");
		String[] porjectStr = iproject.split("/");
		String projectName = porjectStr[workspace.length];
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(
				projectName);
		return project;
	}
	
	public Map<String, Document> keyMapInProject() {
		return null;
	}
	
	public Map<String, Document> keyActionMapInProject(){
		return null;
	}
	
	/**
	 * 克隆方法，将由子类实现
	 * 
	 * */
	public abstract Shape cloneShape(Shape shape);
	
	/**
	 * 项目开发文档中构件的生成
	 * 
	 * */
	public abstract Parameters createNodeHtml(String filePath);
	
	
}